package net.sk.china.common.utils;

import cn.hutool.core.util.StrUtil;
import net.sk.china.common.constants.Constants;
import net.sk.china.common.exception.TalkException;
import net.sk.china.common.response.DateLimit;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*;

/**
 * Date工具类
 * +----------------------------------------------------------------------
 * // | Talk To [ 聊来改善地区金融服务环境，助力企业发展 ]
 * // +----------------------------------------------------------------------
 * // | Copyright (c) 2018-2024 聊来 All rights reserved.
 * // +----------------------------------------------------------------------
 * // | Licensed ( <a href="http://www.apache.org/licenses/LICENSE-2.0">apache</a> )
 * // +----------------------------------------------------------------------
 * // | @Author: 聊来 <18970881148@qq.com>
 * // +----------------------------------------------------------------------
 * // | DateTime: 2024/6/4 16:24
 * // +----------------------------------------------------------------------
 */

public class DateUtil {

    public static final ZoneId DEFAULT_ZONE_ID = ZoneId.systemDefault();

    /**
     * 获取当前时间 精确到秒
     * @return {@code LocalDateTime}
     */
    public static LocalDateTime getNowTime() { return LocalDateTime.now(DEFAULT_ZONE_ID); }

    public static Integer getNowTimeToInteger() {
        long t = (System.currentTimeMillis()/1000L);
        return Integer.parseInt(String.valueOf(t));
    }

    /**
     * 获取当前时间 精确到日
     * @return {@code LocalDate}
     */
    public static LocalDate getDate() { return LocalDate.now(DEFAULT_ZONE_ID); }


    /**
     * LocalDateTime 转 字符串，指定日期格式
     * @param localDateTime 时间
     * @param pattern 日期格式
     * @return {@code String}
     */
    public static String localDateTimeToString(LocalDateTime localDateTime, String pattern){
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);

        return formatter.format(localDateTime.atZone(DEFAULT_ZONE_ID));
    }

    /**
     * LocalDate 转 字符串，指定日期格式
     * @param localDate 时间
     * @param pattern 日期格式
     * @return {@code String}
     */
    public static String localDateToString(LocalDate localDate, String pattern){
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);

        return localDate.format(formatter);
    }

    /**
     * 字符串转 LocalDateTime
     * @param dateTime 时间
     * @return {@code LocalDateTime}
     */
    public static LocalDateTime stringToLocalDateTime(String dateTime) {
        return LocalDateTime.parse(dateTime, DateTimeFormatter.ofPattern(Constants.DATE_FORMAT));
    }

    /**
     * 日期转 LocalDateTime
     * @param dateTime 日期
     * @return {@code LocalDateTime}
     */
    public static LocalDateTime dateToLocalDateTime(String dateTime) {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US);
            SimpleDateFormat sdf1 = new SimpleDateFormat(Constants.DATE_FORMAT);
            String str = sdf1.format(sdf.parse(dateTime));

            return LocalDateTime.parse(str, DateTimeFormatter.ofPattern(Constants.DATE_FORMAT));
        } catch (Exception e) {
            e.printStackTrace();
            return getNowTime();
        }

    }

    /**
     * 日期转 LocalDate
     * @param dateTime 日期
     * @return {@code LocalDateTime}
     */
    public static LocalDate dateToLocalDate(String dateTime) {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US);
            SimpleDateFormat sdf1 = new SimpleDateFormat(Constants.DATE_FORMAT_DATE);
            String str = sdf1.format(sdf.parse(dateTime));

            return LocalDate.parse(str, DateTimeFormatter.ofPattern(Constants.DATE_FORMAT_DATE));
        } catch (Exception e) {
            e.printStackTrace();
            return getDate();
        }

    }

    /**
     * 字符串转 LocalDate
     * @param datetime 时间
     * @return {@code LocalDate}
     */
    public static LocalDate stringToLocalDate(String datetime) {
        return LocalDate.parse(datetime, DateTimeFormatter.ofPattern(Constants.DATE_FORMAT_DATE));
    }

    /**
     * 获取指定月份的天数
     * @param month 指定月份
     * @return {@code int}
     */
    public static int getDaysOfMonth(String month) {
        LocalDate date = LocalDate.parse(month + "-01");

        return date.lengthOfMonth();
    }

    /**
     * 获取本月最后一天
     * @return {@code LocalDate}
     */
    public static LocalDate getMonthEndDay() {
        LocalDate currentDate = LocalDate.now();

        return currentDate.withDayOfMonth(currentDate.lengthOfMonth());
    }

    /**
     * 给指定的日期加、减天数
     * @param dateTime 指定的日期
     * @param num 增加、减少的天数
     * @param pattern 日期格式
     * @return {@code String}
     */
    public static String plusMinusDay(String dateTime, long num, String pattern) {
        LocalDateTime newDate = stringToLocalDateTime(dateTime);

        LocalDateTime date = num > 0 ? newDate.plusDays(num) : newDate.minusDays(Math.abs(num));
        return localDateTimeToString(date, pattern);
    }

    /**
     * 给指定的日期加、减天数
     * @param dateTime 指定的日期
     * @param num 增加、减少的天数
     * @return {@code LocalDate}
     */
    public static LocalDate plusMinusDay(String dateTime, long num) {
        LocalDate newDate = stringToLocalDate(dateTime);

        return num > 0 ? newDate.plusDays(num) : newDate.minusDays(Math.abs(num));
    }

    /**
     * 获取本周第一天
     * @return {@code String}
     */
    public static String getWeekStartDay() { return localDateTimeToString(getNowTime().with(DayOfWeek.MONDAY), Constants.DATE_FORMAT_START); }

    /**
     * 获取本周最后一天
     * @return {@code String}
     */
    public static String getWeekEndDay() { return localDateTimeToString(getNowTime().with(DayOfWeek.SUNDAY), Constants.DATE_FORMAT_END); }

    /**
     * 本年第一天
     * @return {@code String}
     */
    public static String getYearStartDay() { return localDateTimeToString(getNowTime().with(TemporalAdjusters.firstDayOfYear()), Constants.DATE_FORMAT_START);}

    /**
     * 本年最后一天
     * @return {@code String}
     */
    public static String getYearEndDay() { return localDateTimeToString(getNowTime().with(TemporalAdjusters.lastDayOfYear()), Constants.DATE_FORMAT_END);}

    /**
     * 上一个月第一天
     * @return {@code String}
     */
    public static String getLastMonthStartDay() {
        LocalDate currentMonth = getDate().with(TemporalAdjusters.firstDayOfMonth());

        LocalDate preMonth = currentMonth.minusMonths(1);

        return preMonth + " " + Constants.DATE_FORMAT_START_PEREND;
    }

    /**
     * 上一个月最后一天
     * @return {@code String}
     */
    public static String getLastMonthEndDay() {
        LocalDate currentMonth = getDate().with(TemporalAdjusters.lastDayOfMonth());

        LocalDate preMonth = currentMonth.minusMonths(1);

        return preMonth + " " + Constants.DATE_FORMAT_END_PEREND;
    }

    /**
     * 上一年第一天
     * @return {@code String}
     */
    public static String getLastYearStartDay() {
        LocalDate currentYear = getDate().with(TemporalAdjusters.firstDayOfYear());

        LocalDate preYear = currentYear.minusYears(1);

        return preYear + " " + Constants.DATE_FORMAT_START_PEREND;
    }

    /**
     * 上一年最后一天
     * @return {@code String}
     */
    public static String getLastYearEndDay() {
        LocalDate currentYear = getDate().with(TemporalAdjusters.lastDayOfYear());

        LocalDate preYear = currentYear.minusYears(1);

        return preYear + " " + Constants.DATE_FORMAT_END_PEREND;
    }

    /**
     * 获取某一时间段内的时间集合
     * @param data string 类型
     * @return List<Date>
     */
    public static List<String> getListDate(String data) {

        // 获取30天的开始结束日期
        DateLimit dateLimit = getDateLimit(data);

        // 定义日期集合
        List<String> date = new ArrayList<>();

        // 开始日期
        LocalDate startDate = stringToLocalDate(dateLimit.getStartTime().replace(" " + Constants.DATE_FORMAT_START_PEREND,""));

        // 结束日期
        String endTime = dateLimit.getEndTime();
        if (endTime.length() > Constants.NUM_TEN) {
            endTime = endTime.substring(0, endTime.length() - 9);
        }
        LocalDate endDate = stringToLocalDate(endTime);

        while (endDate.isAfter(startDate) || endDate.equals(startDate)) {
            // 放入集合
            date.add(localDateToString(startDate, Constants.DATE_FORMAT_DATE));
            // 循环一次 加一天
            startDate = plusMinusDay(localDateToString(startDate, Constants.DATE_FORMAT_DATE),1);
        }

        return date;
    }

    /**
     * 计算时间范围
     * @param date 日期类型
     * @return {@code DateLimit}
     */
    public static DateLimit getDateLimit(String date){
        //时间计算
        String startTime = null;
        String endTime = DateUtil.localDateTimeToString(getNowTime(), Constants.DATE_FORMAT);
        String day = DateUtil.localDateTimeToString(getNowTime(), Constants.DATE_FORMAT_START);
        String end = DateUtil.localDateTimeToString(getNowTime(), Constants.DATE_FORMAT_END);

        if(StrUtil.isNotBlank(date)){
            switch (date){
                case Constants.SEARCH_DATE_DAY:
                    startTime = day;
                    break;
                case Constants.SEARCH_DATE_YESTERDAY:
                    startTime = DateUtil.plusMinusDay(day, -1, Constants.DATE_FORMAT_START);
                    endTime = DateUtil.plusMinusDay(end, -1, Constants.DATE_FORMAT_END);
                    break;
                case Constants.SEARCH_DATE_LATELY_7:
                    startTime = DateUtil.plusMinusDay(day, -6, Constants.DATE_FORMAT_START);
                    break;
                case Constants.SEARCH_DATE_WEEK:
                    startTime = getWeekStartDay();
                    endTime = getWeekEndDay();
                    break;
                case Constants.SEARCH_DATE_PRE_WEEK:
                    startTime = plusMinusDay(getWeekStartDay(), -7, Constants.DATE_FORMAT_START);
                    endTime = plusMinusDay(getWeekEndDay(), -7, Constants.DATE_FORMAT_END);
                    break;
                case Constants.SEARCH_DATE_LATELY_30:
                    startTime = DateUtil.plusMinusDay(day, -30, Constants.DATE_FORMAT_START);
                    break;
                case Constants.SEARCH_DATE_MONTH:
                    startTime = localDateToString(getDate().with(TemporalAdjusters.firstDayOfMonth()), Constants.DATE_FORMAT_DATE);
                    endTime = localDateToString(getDate().with(TemporalAdjusters.lastDayOfMonth()), Constants.DATE_FORMAT_DATE);
                    break;
                case Constants.SEARCH_DATE_PRE_MONTH:
                    startTime = getLastMonthStartDay();
                    endTime = getLastMonthEndDay();
                    break;
                case Constants.SEARCH_DATE_YEAR:
                    startTime = getYearStartDay();
                    endTime = getYearEndDay();
                    break;
                case Constants.SEARCH_DATE_PRE_YEAR:
                    startTime = getLastYearStartDay();
                    endTime = getLastYearEndDay();
                    break;
                default:
                    List<String> list = TalkUtil.stringToArrayStr(date);
                    if(list.size() == 1){
                        throw new TalkException("选择时间参数格式错误，请在 " +
                                Constants.SEARCH_DATE_DAY + "|" +
                                Constants.SEARCH_DATE_YESTERDAY + "|" +
                                Constants.SEARCH_DATE_LATELY_7 + "|" +
                                Constants.SEARCH_DATE_LATELY_30 + "|" +
                                Constants.SEARCH_DATE_MONTH + "|" +
                                Constants.SEARCH_DATE_YEAR + "|自定义时间范围（格式：yyyy-MM-dd，两个时间范围用逗号分割）");
                    }
                    startTime = stringToLocalDate(list.get(0)) + " " + Constants.DATE_FORMAT_START_PEREND;
                    endTime = stringToLocalDate(list.get(1)) + " " + Constants.DATE_FORMAT_END_PEREND;

                    break;
            }
        }
        return new DateLimit(startTime, endTime);
    }

    /**
     * 字符串时间转Date
     * @param dateStr 字符串时间
     * @param dateFormat 转换的格式
     * @return {@code Date}
     */
    public static Date strToDate(String dateStr, String dateFormat) {
        SimpleDateFormat myFormat = new SimpleDateFormat(dateFormat);
        try {
            return myFormat.parse(dateStr);
        } catch (ParseException e) {
            return null;
        }
    }

    /**
     * 获取当前月份
     * @return {@code String}
     */
    public static String getCurrentMonth()
    {
        LocalDate date = LocalDate.now();
        String month = date.getMonthValue() < 10 ? "0" + date.getMonthValue() : String.valueOf(date.getMonthValue());

        return date.getYear() + "-" + month;
    }

    /**
     * 判断是否为本月最后一天
     * @param date 查询的日期
     * @return {@code boolean}
     */
    public static boolean isLastDayOfMonth(LocalDateTime date) {
        LocalDateTime lastDayOfMonth = date.with(TemporalAdjusters.lastDayOfMonth());
        return date.isEqual(lastDayOfMonth);
    }

    /**
     * 比较日期大小
     * @param date1 日期1
     * @param date2 日期2
     * @param pattern 日期格式
     * @return {@code int}
     */
    public static int compareDate(String date1, String date2, String pattern) {
        SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
        try {
            Date dt1 = dateFormat.parse(date1);
            Date dt2 = dateFormat.parse(date2);
            if (dt1.getTime() > dt2.getTime()) {
                return 1;
            } else if (dt1.getTime() < dt2.getTime()) {
                return -1;
            } else {
                return 0;
            }

        } catch (ParseException e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 获取当前年,指定格式
     * @return {@code String}
     */
    public static String nowYear() {
        Calendar cal = Calendar.getInstance();
        return cal.get(Calendar.YEAR) + "";
    }

    /**
     * 获取上一年,指定格式
     * @return {@code String}
     */
    public static String lastYear() {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.YEAR, -1);
        return cal.get(Calendar.YEAR) + "";
    }
}
